home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Python / traceback.c < prev   
Encoding:
C/C++ Source or Header  |  2000-09-10  |  5.7 KB  |  257 lines

  1. /* Traceback implementation */
  2.  
  3. #include "Python.h"
  4.  
  5. #include "compile.h"
  6. #include "frameobject.h"
  7. #include "structmember.h"
  8. #include "osdefs.h"
  9.  
  10. typedef struct _tracebackobject {
  11.     PyObject_HEAD
  12.     struct _tracebackobject *tb_next;
  13.     PyFrameObject *tb_frame;
  14.     int tb_lasti;
  15.     int tb_lineno;
  16. } tracebackobject;
  17.  
  18. #include "protos/traceback.h"
  19.  
  20. #define OFF(x) offsetof(tracebackobject, x)
  21.  
  22. static struct memberlist tb_memberlist[] = {
  23.     {"tb_next",    T_OBJECT,    OFF(tb_next)},
  24.     {"tb_frame",    T_OBJECT,    OFF(tb_frame)},
  25.     {"tb_lasti",    T_INT,        OFF(tb_lasti)},
  26.     {"tb_lineno",    T_INT,        OFF(tb_lineno)},
  27.     {NULL}    /* Sentinel */
  28. };
  29.  
  30. static PyObject *
  31. tb_getattr(tb, name)
  32.     tracebackobject *tb;
  33.     char *name;
  34. {
  35.     return PyMember_Get((char *)tb, tb_memberlist, name);
  36. }
  37.  
  38. static void
  39. tb_dealloc(tb)
  40.     tracebackobject *tb;
  41. {
  42.     Py_TRASHCAN_SAFE_BEGIN(tb)
  43.     Py_XDECREF(tb->tb_next);
  44.     Py_XDECREF(tb->tb_frame);
  45.     PyObject_DEL(tb);
  46.     Py_TRASHCAN_SAFE_END(tb)
  47. }
  48.  
  49. #define Tracebacktype PyTraceBack_Type
  50. #define is_tracebackobject PyTraceBack_Check
  51.  
  52. PyTypeObject Tracebacktype = {
  53.     PyObject_HEAD_INIT(&PyType_Type)
  54.     0,
  55.     "traceback",
  56.     sizeof(tracebackobject),
  57.     0,
  58.     (destructor)tb_dealloc, /*tp_dealloc*/
  59.     0,        /*tp_print*/
  60.     (getattrfunc)tb_getattr, /*tp_getattr*/
  61.     0,        /*tp_setattr*/
  62.     0,        /*tp_compare*/
  63.     0,        /*tp_repr*/
  64.     0,        /*tp_as_number*/
  65.     0,        /*tp_as_sequence*/
  66.     0,        /*tp_as_mapping*/
  67. };
  68.  
  69. static tracebackobject *
  70. newtracebackobject(next, frame, lasti, lineno)
  71.     tracebackobject *next;
  72.     PyFrameObject *frame;
  73.     int lasti, lineno;
  74. {
  75.     tracebackobject *tb;
  76.     if ((next != NULL && !is_tracebackobject(next)) ||
  77.             frame == NULL || !PyFrame_Check(frame)) {
  78.         PyErr_BadInternalCall();
  79.         return NULL;
  80.     }
  81.     tb = PyObject_NEW(tracebackobject, &Tracebacktype);
  82.     if (tb != NULL) {
  83.         Py_XINCREF(next);
  84.         tb->tb_next = next;
  85.         Py_XINCREF(frame);
  86.         tb->tb_frame = frame;
  87.         tb->tb_lasti = lasti;
  88.         tb->tb_lineno = lineno;
  89.     }
  90.     return tb;
  91. }
  92.  
  93. int
  94. PyTraceBack_Here(frame)
  95.     PyFrameObject *frame;
  96. {
  97.     PyThreadState *tstate = frame->f_tstate;
  98.     tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
  99.     tracebackobject *tb = newtracebackobject(oldtb,
  100.                 frame, frame->f_lasti, frame->f_lineno);
  101.     if (tb == NULL)
  102.         return -1;
  103.     tstate->curexc_traceback = (PyObject *)tb;
  104.     Py_XDECREF(oldtb);
  105.     return 0;
  106. }
  107.  
  108. static int
  109. tb_displayline(f, filename, lineno, name)
  110.     PyObject *f;
  111.     char *filename;
  112.     int lineno;
  113.     char *name;
  114. {
  115.     int err = 0;
  116.     FILE *xfp;
  117.     char linebuf[1000];
  118.     int i;
  119.     if (filename == NULL || name == NULL)
  120.         return -1;
  121. #ifdef MPW
  122.     /* This is needed by MPW's File and Line commands */
  123. #define FMT "  File \"%.900s\"; line %d # in %s\n"
  124. #else
  125.     /* This is needed by Emacs' compile command */
  126. #define FMT "  File \"%.900s\", line %d, in %s\n"
  127. #endif
  128.     xfp = fopen(filename, "r");
  129.     if (xfp == NULL) {
  130.         /* Search tail of filename in sys.path before giving up */
  131.         PyObject *path;
  132.         char *tail = strrchr(filename, SEP);
  133.         if (tail == NULL)
  134.             tail = filename;
  135.         else
  136.             tail++;
  137.         path = PySys_GetObject("path");
  138.         if (path != NULL && PyList_Check(path)) {
  139.             int npath = PyList_Size(path);
  140.             int taillen = strlen(tail);
  141.             char namebuf[MAXPATHLEN+1];
  142.             for (i = 0; i < npath; i++) {
  143.                 PyObject *v = PyList_GetItem(path, i);
  144.                 if (v == NULL) {
  145.                     PyErr_Clear();
  146.                     break;
  147.                 }
  148.                 if (PyString_Check(v)) {
  149.                     int len;
  150.                     len = PyString_Size(v);
  151.                     if (len + 1 + taillen >= MAXPATHLEN)
  152.                         continue; /* Too long */
  153.                     strcpy(namebuf, PyString_AsString(v));
  154.                     if ((int)strlen(namebuf) != len)
  155.                         continue; /* v contains '\0' */
  156.                     if (len > 0 && namebuf[len-1] != SEP)
  157.                         namebuf[len++] = SEP;
  158.                     strcpy(namebuf+len, tail);
  159.                     xfp = fopen(namebuf, "r");
  160.                     if (xfp != NULL) {
  161.                         filename = namebuf;
  162.                         break;
  163.                     }
  164.                 }
  165.             }
  166.         }
  167.     }
  168.     sprintf(linebuf, FMT, filename, lineno, name);
  169.     err = PyFile_WriteString(linebuf, f);
  170.     if (xfp == NULL || err != 0)
  171.         return err;
  172.     for (i = 0; i < lineno; i++) {
  173.         char* pLastChar = &linebuf[sizeof(linebuf)-2];
  174.         do {
  175.             *pLastChar = '\0';
  176.             if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
  177.                 break;
  178.             /* fgets read *something*; if it didn't get as
  179.                far as pLastChar, it must have found a newline
  180.                or hit the end of the file;    if pLastChar is \n,
  181.                it obviously found a newline; else we haven't
  182.                yet seen a newline, so must continue */
  183.         } while (*pLastChar != '\0' && *pLastChar != '\n');
  184.     }
  185.     if (i == lineno) {
  186.         char *p = linebuf;
  187.         while (*p == ' ' || *p == '\t' || *p == '\014')
  188.             p++;
  189.         err = PyFile_WriteString("    ", f);
  190.         if (err == 0) {
  191.             err = PyFile_WriteString(p, f);
  192.             if (err == 0 && strchr(p, '\n') == NULL)
  193.                 err = PyFile_WriteString("\n", f);
  194.         }
  195.     }
  196.     fclose(xfp);
  197.     return err;
  198. }
  199.  
  200. static int
  201. tb_printinternal(tb, f, limit)
  202.     tracebackobject *tb;
  203.     PyObject *f;
  204.     int limit;
  205. {
  206.     int err = 0;
  207.     int depth = 0;
  208.     tracebackobject *tb1 = tb;
  209.     while (tb1 != NULL) {
  210.         depth++;
  211.         tb1 = tb1->tb_next;
  212.     }
  213.     while (tb != NULL && err == 0) {
  214.         if (depth <= limit) {
  215.             if (Py_OptimizeFlag)
  216.                 tb->tb_lineno = PyCode_Addr2Line(
  217.                     tb->tb_frame->f_code, tb->tb_lasti);
  218.             err = tb_displayline(f,
  219.                 PyString_AsString(
  220.                     tb->tb_frame->f_code->co_filename),
  221.                 tb->tb_lineno,
  222.                 PyString_AsString(tb->tb_frame->f_code->co_name));
  223.         }
  224.         depth--;
  225.         tb = tb->tb_next;
  226.         if (err == 0)
  227.             err = PyErr_CheckSignals();
  228.     }
  229.     return err;
  230. }
  231.  
  232. int
  233. PyTraceBack_Print(v, f)
  234.     PyObject *v;
  235.     PyObject *f;
  236. {
  237.     int err;
  238.     PyObject *limitv;
  239.     int limit = 1000;
  240.     if (v == NULL)
  241.         return 0;
  242.     if (!is_tracebackobject(v)) {
  243.         PyErr_BadInternalCall();
  244.         return -1;
  245.     }
  246.     limitv = PySys_GetObject("tracebacklimit");
  247.     if (limitv && PyInt_Check(limitv)) {
  248.         limit = PyInt_AsLong(limitv);
  249.         if (limit <= 0)
  250.             return 0;
  251.     }
  252.     err = PyFile_WriteString("Traceback (most recent call last):\n", f);
  253.     if (!err)
  254.         err = tb_printinternal((tracebackobject *)v, f, limit);
  255.     return err;
  256. }
  257.